﻿using AyFrame.Common;
using AyFrame.DbEntity.ColumnAttributes;
using AyFrame.DbEntity.Models;
using AyFrame.Dto;
using AyFrame.NSerialLog;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace AyFrame.DbEntity
{
    public class DbFramework
    {
        #region Config

        public static ConfigureExternalServices ConfigMyDb(SqlSugarClient db)
        {
            var dbType = db.CurrentConnectionConfig.DbType;

            return new ConfigureExternalServices
            {
                EntityService = (property, column) =>
                {
                    var attrs = property.GetCustomAttributes(true);
                    if (attrs.Any(t => t is StringKeyAttribute))
                    {
                        //column.IsPrimarykey = true;
                        //column.DataType = "nvarchar(50)";
                        //column.DefaultValue = "newid()";
                        column.StringKey(dbType);
                    }

                    if (attrs.Any(t => t is StringLengthAttribute))
                    {
                        //column.IsNullable = true;

                        var attr = attrs.First(t => t is StringLengthAttribute) as StringLengthAttribute;
                        //if (attr.Length == -1)
                        //    column.DataType = "nvarchar(max)";
                        //else
                        //    column.DataType = $"nvarchar({attr.Length})";
                        column.StringLength(dbType, attr.Length);
                    }

                    if (attrs.Any(t => t is DecimalDigitAttribute))
                    {
                        var attr = attrs.First(t => t is DecimalDigitAttribute) as DecimalDigitAttribute;

                        //column.DataType = "decimal";
                        //column.DecimalDigits = attr.Digit;
                        column.DecimalDigit(dbType, attr.Digit);
                    }

                    if (attrs.Any(t => t is StringJsonAttribute))
                    {
                        //column.IsNullable = true;
                        //column.IsJson = true;
                        //column.DataType = "nvarchar(max)";
                        column.StringJson(dbType);
                    }
                }
            };
        }
        #endregion

        #region Init
        public static void InitDb(ISqlSugarClient db)
        {
            db.DbMaintenance.CreateDatabase();

            InitTables(db.CodeFirst);

            InitData(db);
        }

        static void InitTables(ICodeFirst cf)
        {
            var types = Assembly.Load("AyFrame.DbEntity").GetTypes().Where(t => t.Namespace == "AyFrame.DbEntity.Models" && t.Name != "BaseEntity").ToArray();
            cf.InitTables(types);
        }


        static void InitData(ISqlSugarClient db)
        {
            var admin = db.Queryable<SysUserInfo>().Where(t => t.LoginName == "admin").First();
            if (admin == null)
                db.Insertable(new SysUserInfo
                {
                    LoginName = "admin",
                    Salt = "AsakuraYou",
                    Password = Utils.MD5("123456" + "AsakuraYou"),
                    Name = "管理员"
                }).AddQueue();

            db.SaveQueues();
        }
        #endregion

        #region SqlSugarAop

        public static void DiffLogAct(DiffLogModel item)
        {
            //var method = item.BusinessData.GetType().GetProperty("Method").GetValue(item.BusinessData);
            //var entityName = item.BusinessData.GetType().GetProperty("EntityName").GetValue(item.BusinessData);
            var uid = item.BusinessData.GetType().GetProperty("uid").GetValue(item.BusinessData);

            var bfData = item.BeforeData;
            var afData = item.AfterData;

            if (item.DiffType == DiffType.insert)
            {
                var afDataColumn = afData[0].Columns;

                var log = new SystemLogView
                {
                    Method = item.DiffType.ToString(),
                    TableName = afData.First().TableName,
                    LogData = afDataColumn.Aggregate("", (a, b) => a += $"{b.ColumnName}=>{b.Value},").TrimEnd(','),
                    OperUid = uid == null ? "" : uid.ToString()
                };

                LogHelper.LogDb(log);
            }
            else if (item.DiffType == DiffType.update)
            {
                var bfDataColumn = bfData[0].Columns;
                var afDataColumn = afData[0].Columns;

                var diffs = new List<string>();
                bfDataColumn.ForEach(bf =>
                {
                    var af = afDataColumn.Where(t => t.ColumnName == bf.ColumnName).FirstOrDefault();
                    if (af == null) return;

                    if (bf.ColumnName.ToUpper() == "UpdateTime".ToUpper()) return;

                    switch (bf.Value.GetType().Name.ToUpper())
                    {
                        case "STRING":
                            if (af.Value.ToString() == bf.Value.ToString()) return;
                            break;
                        case "INT32":
                            if (int.Parse(af.Value.ToString()) == int.Parse(bf.Value.ToString())) return;
                            break;
                        case "DATETIME":
                            if (DateTime.Parse(af.Value.ToString()) == DateTime.Parse(bf.Value.ToString())) return;
                            break;
                        case "DECIMAL":
                            if (decimal.Parse(af.Value.ToString()) == decimal.Parse(bf.Value.ToString())) return;
                            break;
                    }

                    if (bf.Value != af.Value)
                        diffs.Add($"{bf.ColumnName}:【{bf.Value}】->【{af.Value}】");
                });

                if (diffs.Count > 0)
                {
                    var log = new SystemLogView
                    {
                        Method = item.DiffType.ToString(),
                        TableName = afData.First().TableName,
                        LogData = diffs.Aggregate("", (a, b) => a += $"{b},").TrimEnd(','),
                        OperUid = uid == null ? "" : uid.ToString()
                    };

                    LogHelper.LogDb(log);
                }
            }
            else if (item.DiffType == DiffType.delete)
            {
                var bfDataColumn = bfData[0].Columns;
                var log = new SystemLogView
                {
                    Method = item.DiffType.ToString(),
                    TableName = afData.First().TableName,
                    LogData = bfDataColumn.Aggregate("", (a, b) => a += $"{b.ColumnName}=>{b.Value},").TrimEnd(','),
                    OperUid = uid == null ? "" : uid.ToString()
                };

                LogHelper.LogDb(log);
            }
        }

        #endregion
    }
}
